<?php

namespace Xin\Setting\ThinkPHP;

use ReflectionException;
use ReflectionProperty;
use think\Config;
use think\Service;
use Xin\Setting\Contracts\Factory as SettingFactory;
use Xin\Setting\Contracts\Serializer as SettingSerializer;
use Xin\Setting\Serializer;
use Xin\Setting\SettingManager;
use Xin\Setting\ThinkPHP\Commands\ClearCommand;
use Xin\Setting\ThinkPHP\Commands\ShowCommand;
use Xin\Setting\ThinkPHP\Commands\UpdateCommand;
use Xin\Support\Arr;
use Xin\Support\Str;

class SettingServiceProvider extends Service
{

	/**
	 * @inheritDoc
	 */
	public function register()
	{
		$this->registerManager();

		$this->registerCommands();

		if ($this->app->runningInConsole()) {
			$this->app->event->listen('AppInit', function () {
				$this->registerConsoleInitializers();
			});
		}
	}

	/**
	 * 注册站点配置管理器
	 * @return void
	 */
	protected function registerManager()
	{
		$this->app->bind([
			'setting' => SettingFactory::class,
			SettingFactory::class => SettingManager::class,
			SettingManager::class => function () {
				$manager = new SettingManager(
					$this->app->config->get('setting', []),
					$this->app['cache'],
				);

				// 加载站点配置到系统配置中
				$this->setToSystemConfigResolver($manager);

				// 注册驱动器
				$this->registerDrivers($manager);

				return $manager;
			},
		]);

		$this->app->bind('setting.repository', function ($app) {
			return $app['setting']->repository();
		});

		$this->app->bind([
			'setting.serializer' => SettingSerializer::class,
			SettingSerializer::class => Serializer::class,
		]);
	}

	/**
	 * 注册驱动器
	 * @return void
	 */
	protected function registerDrivers(SettingManager $manager)
	{
		$handler = function ($name, $config) {
			return new ModelRepository(
				$config,
				$this->app['setting.serializer']
			);
		};
		$manager->extend('model', $handler);
		$manager->extend('database', $handler);
	}

	/**
	 * 注册设置系统配置完成器
	 * @return void
	 */
	protected function setToSystemConfigResolver(SettingManager $manager)
	{
		$manager->setToSystemConfigResolver(function ($settings) {
			/** @var Config $config */
			$thinkConfig = $this->app->config;

			// 获取全局配置
			$configRef = new ReflectionProperty($thinkConfig, 'config');
			/** @noinspection PhpExpressionResultUnusedInspection */
			$configRef->setAccessible(true);
			$globalConfig = $configRef->getValue($thinkConfig);

			// 批量设置系统配置
			foreach ($settings as $key => $value) {
				Arr::set($globalConfig, $key, $value);
			}

			// 重新设置系统配置
			$configRef->setValue($thinkConfig, $globalConfig);
		});
	}

	/**
	 * 注册初始化器
	 * @return void
	 * @throws ReflectionException
	 */
	protected function registerConsoleInitializers()
	{
		$initializersRef = new ReflectionProperty($this->app, 'initializers');
		/** @noinspection PhpExpressionResultUnusedInspection */
		$initializersRef->setAccessible(true);

		$initializers = $initializersRef->getValue($this->app);
		$initializers[] = SettingServiceProvider::class;
		$initializersRef->setValue($this->app, $initializers);
	}

	/**
	 * @inheritDoc
	 */
	public function boot()
	{
		// if (!$this->app->runningInConsole()) {
		// 	$this->app->event->listen('HttpRun', function () {
		// 		// 加载站点配置到系统配置中
		// 		$this->app['setting']->loadToSystemConfig(true);
		// 	});
		// }

		// 加载站点配置到系统配置中
		if ($this->app->runningInConsole()) {
			global $argv;
			$command = implode(' ', $argv);
			if (!Str::startsWith($command, [
				'think service:discover',
				'think vendor:publish',
			])) {
				$this->app['setting']->loadToSystemConfig(true);
			}
		} else {
			$this->app['setting']->loadToSystemConfig(true);
		}
	}

	/**
	 * 控制台应用初始器
	 * @return void
	 */
	public function init()
	{
		// 加载站点配置到系统配置中
		$this->app['setting']->loadToSystemConfig();
	}

	/**
	 * 注册命令行脚本
	 * @return void
	 */
	protected function registerCommands()
	{
		$this->commands([
			ShowCommand::class,
			ClearCommand::class,
			UpdateCommand::class,
		]);
	}
}
